#include "StdAfx.h"

#include <iostream>

#include "Server.hpp"
#include "ServerWorker.hpp"
#include "NetOperations.hpp"

using namespace HpsFramework;
using namespace HpsFramework::Network;

Network::Server* HpsFramework::Network::ServerWorker::getServer()
{
	return this->_server;
}

HpsFramework::Network::ServerWorker::ServerWorker( Network::Server* srv ) : _server(srv)
{

}

HpsFramework::Network::ServerWorker::~ServerWorker( void )
{

}

bool HpsFramework::Network::ServerWorker::preProcess()
{
	// Notifies the existence of a new thread doing IO work
	this->getServer()->getIoController()->notify();
	return true;
}

bool HpsFramework::Network::ServerWorker::doProcess()
{
	
	size ioSize;
	Client* context = NULL;
	NetQueue::Overlapped* overlapped;
	NetQueue* queue = NULL;

	if(!this->getServer()->getIoController()->getEvent<Client*, NetQueue::Overlapped*>(&ioSize, &context, &overlapped))
	{
		int err = GetLastError();
		if(err == ERROR_NETNAME_DELETED || err == ERROR_CONNECTION_ABORTED)
		{
			if(context)
			{
				context->close(true);
				return true;
			}
		}
		this->getServer()->onServerError("IO Controller event failed (GetQueuedCompletionStatus())", err);
		return true;
	}

	// Termination message
	if(context == NULL)
	{
		// Finishes the thread
		return false;
	}

	queue = (NetQueue*)overlapped->parent;

	switch(queue->getOperationType())
	{
	case OperationReceive:
		{

			NetReader* reader = (NetReader*)queue;
			if(ioSize == 0)	
			{
				context->disconnect(true);
				return true;
			}
			reader->finishTransmission ( ioSize );

			size bufSize = 0;
			byteptr buffer = NULL;
			
			//std::cout << "Incoming: " << ioSize << " bytes..." << std::endl;

			reader->getBuffer()->getReadPtr(buffer, bufSize); 
			ioSize = context->onReceive ( buffer, bufSize );

			if(ioSize == -1)
			{
				context->disconnect();
			}
			else
			{

				reader->getBuffer()->dequeue(ioSize);

				// New recv solicitation
				unsigned int recvBytes = 0, recvFlags = 0;

				context->getReader()->startTransmisson();

				int ret = WSARecv ( 
					context->getSocket(), 
					context->getReader()->getNetBuf(), 1, (LPDWORD)&recvBytes, (LPDWORD)&recvFlags, 
					context->getReader()->getNetOverlap(), NULL );

			}
			
		}
		break;
	case OperationSend:
		{
			NetWriter* writer = (NetWriter*)queue;
			writer->finishTransmission ( ioSize );
			//std::cout << "Outgoing: " << ioSize << " bytes..." << std::endl;
		}
		break;

	default:
		this->getServer()->onServerError("Got default operation type, please check!", queue->getOperationType());
		break;

	}

	return true;

}

bool HpsFramework::Network::ServerWorker::postProcess()
{
	return true;
}

HpsFramework::Network::Server* HpsFramework::Network::ServerWriter::getServer()
{
	return this->_server;
}

HpsFramework::Network::ServerWriter::ServerWriter( HpsFramework::Network::Server* srv ) : _server ( srv )
{

}

HpsFramework::Network::ServerWriter::ServerWriter( ) : _server ( NULL )
{

}

HpsFramework::Network::ServerWriter::~ServerWriter( void )
{

}

bool HpsFramework::Network::ServerWriter::preProcess()
{
	return true;
}

bool HpsFramework::Network::ServerWriter::doProcess()
{

	HpsFramework::Network::ClientManager* mgr = this->getServer()->getClientManager();
	if(!mgr->isEmpty())
	{

		LockList(mgr)
		StartListIteration(Client*, mgr)
		{

			HpsFramework::Network::Client* context = CurrentNode->getContent();
			if ( context && !context->isRemoveSet() )
			{

				// std::cout << "send iteration over id " << context->getId() << std::endl;

				HpsFramework::Network::NetWriter* writer = context->getWriter();
				if(!writer->isReady())
				{

					ContinueListIteration();

				}
				else
				{

					unsigned int recvBytes = 0;
					unsigned int recvFlags = 0;

					writer->startTransmisson();

					int ret = WSASend 
						( 
							context->getSocket(), 
							writer->getNetBuf(), 1, (LPDWORD)&recvBytes, recvFlags, 
							writer->getNetOverlap(), NULL
						);

					if(ret == SOCKET_ERROR)
					{

						if(WSAGetLastError() != WSA_IO_PENDING)
						{
							context->setRemoval();
						}

					}

				}

			}

			CurrentNode = GetNextNode();

		}

		FinishListIteration()
		UnlockList()			

	}

	Sleep(1);
	return true;

}

bool HpsFramework::Network::ServerWriter::postProcess()
{
	return true;
}

void HpsFramework::Network::ServerWriter::setServer( HpsFramework::Network::Server* srv )
{
	this->_server = srv;
}
